package com.zb.common.aspect;

import java.lang.reflect.Method;
import java.util.Date;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.google.common.base.Joiner;
import com.google.common.collect.Maps;
import com.zb.common.annotation.WriteLog;
import com.zb.common.mapper.OperationLogMapper;
import com.zb.common.po.enums.LogType;
import com.zb.common.po.enums.OpResult;
import com.zb.common.po.enums.ResponseCode;
import com.zb.common.po.model.OperationLog;
import com.zb.common.po.model.SessionUser;
import com.zb.common.po.vo.AjaxResponse;
import com.zb.common.utils.Constants;

@Aspect
@Component
public class OperationLogInterceptor {

	private static final Logger logger = LoggerFactory.getLogger(OperationLogInterceptor.class);

	@Resource
	private OperationLogMapper operationLogMapper;

	@Pointcut("@annotation(com.zb.common.annotation.WriteLog)")
	private void myMethods() {
	};

	@Around("myMethods()")
	public Object doMethod(ProceedingJoinPoint point) {
		String userName = getUserName();
		Object obj = null;
		try {
			obj = point.proceed();
		} catch (Throwable e) {
			e.printStackTrace();
			logger.error("方法执行异常了");
		}
		try {
			Object target = point.getTarget();
			Object[] arguments = point.getArgs();
			String method = point.getSignature().getName();
			Class<?>[] parameterTypes = ((MethodSignature) point.getSignature()).getMethod().getParameterTypes();
			Method m = target.getClass().getMethod(method, parameterTypes);
			WriteLog writeLog = m.getAnnotation(WriteLog.class);
			int[] argIndexs = writeLog.paramIndexes();
			Map<String, Object> namedParams = Maps.newHashMap();
			for (int i = 0, _len = argIndexs.length; i < _len; i++) {
				namedParams.put("param" + i, convert2String(arguments[argIndexs[i]]));
			}
			String description = formateString(writeLog.opDescription(), namedParams);

			OpResult opResult = OpResult.SUCCESS;
			//判断是否操作成功
			if (obj instanceof AjaxResponse<?>) {
				AjaxResponse<?> response = (AjaxResponse<?>) obj;
				if (ResponseCode.SUCCESS != response.getResponseCode()) {
					opResult = OpResult.FAIL;
				}
			}
			LogType logType = writeLog.logType();
			if (logType == LogType.LOGIN) {
				userName = String.valueOf(arguments[1]);
			}
			OperationLog log = new OperationLog();
			log.setUserName(userName);
			log.setOpObject(writeLog.opObject());
			log.setOpDescription(description);
			log.setCreateTime(new Date());
			log.setOpResult(opResult);
			log.setLogType(writeLog.logType());
			operationLogMapper.insertOperationLog(log);
		} catch (Exception e) {
			logger.error("记录日志异常", e);
		}
		return obj;
	}

	private String convert2String(Object obj) {
		if (null == obj) {
			return null;
		}
		if (obj instanceof Integer[]) {
			Integer[] objs = (Integer[]) obj;
			return Joiner.on(",").join(objs);
		} else if (obj instanceof String[]) {
			String[] objs = (String[]) obj;
			return Joiner.on(",").join(objs);
		} else {
			return obj.toString();
		}
	}

	private String getUserName() {
		try {
			HttpSession session = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest()
					.getSession();
			SessionUser sessionUser = (SessionUser) session.getAttribute(Constants.SESSION_KEY);
			if (null != sessionUser) {
				return sessionUser.getUserName();
			} else {
				return null;
			}
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	private String formateString(String sourceStr, Map<String, Object> namedParams) {
		StandardEvaluationContext context = new StandardEvaluationContext();
		context.setVariables(namedParams);
		ExpressionParser parser = new SpelExpressionParser();
		String resut = parser.parseExpression(sourceStr, new TemplateParserContext()).getValue(context, String.class);
		return resut;
	}

	public static void main(String[] args) throws NoSuchMethodException {
		StandardEvaluationContext context = new StandardEvaluationContext();
		Map<String, Object> namedParams = Maps.newHashMap();
		namedParams.put("param2", 0);
		namedParams.put("param1", 1);
		namedParams.put("param0", 10);
		context.setVariables(namedParams);
		ExpressionParser parser = new SpelExpressionParser();
		String randomPhrase = parser.parseExpression("#{#param0}", new TemplateParserContext()).getValue(context,
				String.class);
		System.out.print(randomPhrase);
	}
}